package com.djl.beans;
import com.djl.annotation.Component;
import com.djl.annotation.Controller;
import com.djl.annotation.Service;
import com.djl.util.CommonUtil;
import com.djl.util.PropertiesUtil;
import lombok.extern.slf4j.Slf4j;


import javax.servlet.ServletConfig;
import java.io.File;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 用于获取指定的配置文件下所有的BeanDefinition
 */
@Slf4j
public class BeanDefinitionReader {

    private final String CLASSPATH = "classPathLocation";//默认配置文件name,用于获取配置文件Name
    private final String defaultPackageScan = "basePackage";//默认包扫描
    private List<String> classNames = new ArrayList<>();// 用一个List集合保存一下所有的classNames
    /**
     * 将beanName,HBeanDefinition加入此Map用于实例化Bean方便获取
     */
    public Map<String, BeanDefinition> beanDefinitionMap = new HashMap<>();
    /**
     * 根据解析到的classNames得到BeanDefinition的集合
     */
    public List<BeanDefinition> beanDefinitions = new ArrayList<>();;


    public BeanDefinitionReader(ServletConfig servletConfig) {
        //读取配置将所有.class结尾的java文件放进 classNames
        doConfig(servletConfig);
        //加载所有BeanDefinitions
        loadBeanDefinitions();
        //将beanName与HBeanDefinition的关系存储起来   classNames---->Bean元数据的信息
        doBeanNameBeanDefinition();
    }

    private void doBeanNameBeanDefinition() {
        for (BeanDefinition beanDefinition : this.beanDefinitions) {
            if (this.beanDefinitionMap.containsKey(beanDefinition.getBeanName())) {
                throw new RuntimeException(beanDefinition.getBeanName() + "exists");
            }
            this.beanDefinitionMap.put(beanDefinition.getBeanName(), beanDefinition);
        }
    }

    private void doConfig(ServletConfig servletConfig) {
        //获取默认包扫描路径
        String basePackage = PropertiesUtil.getPackageScan(servletConfig.getInitParameter(CLASSPATH), defaultPackageScan);
        log.info("默认包扫描路径为："+basePackage);
        //找到具有给定名称的资源,资源的名称是标识资源的“ / ”分隔路径名
        URL url = this.getClass().getClassLoader().getResource(basePackage.replace(".", "/"));

        File classPath = new File(url.getFile());
        // 获取该路径下所有的.class文件，所以递归扫描该路径，找出符合要求的class文件
        recursionFile(classPath,basePackage);
    }

    public void loadBeanDefinitions() {
        if(this.classNames.size()==0){
            return;
        }
        beanDefinitions.clear();
        try {
            for (String className:this.classNames){
                Class<?> clazz = Class.forName(className);
                //判断当前class不是注解
                if(!clazz.isAnnotation()){
                    //处理带注解的类
                    annotationDispose(clazz);
                }
            }
        }catch (Exception e){
            e.printStackTrace();
        }

    }


    public void annotationDispose(Class<?> clazz){
        String beanName = "";
        if(clazz.isAnnotationPresent(Component.class)){
            Component component = clazz.getAnnotation(Component.class);
            // 判断@HHComponent上是否有value属性
            if (!component.value().equals("")) {
                beanName = component.value();  // beanName=hahaController
            }else{
                beanName = CommonUtil.lowerFirstCase(clazz.getSimpleName());//类名首字母小写
            }
            BeanDefinition beanDefinition = new BeanDefinition();
            beanDefinition.setBeanName(beanName);
            beanDefinition.setBeanClassName(clazz.getName());
            beanDefinitions.add(beanDefinition);
        }
        if(clazz.isAnnotationPresent(Controller.class)){
            Controller controller = clazz.getAnnotation(Controller.class);
            if (!controller.value().equals("")) {
                beanName = controller.value();
            }else{
                beanName = CommonUtil.lowerFirstCase(clazz.getSimpleName());
            }
            BeanDefinition beanDefinition = new BeanDefinition();
            beanDefinition.setBeanName(beanName);
            beanDefinition.setBeanClassName(clazz.getName());
            beanDefinitions.add(beanDefinition);
        }

        if(clazz.isAnnotationPresent(Service.class)){
            Service service = clazz.getAnnotation(Service.class);
            if (!service.value().equals("")) {
                beanName = service.value();
            }else{
                beanName = CommonUtil.lowerFirstCase(clazz.getSimpleName());
            }
            BeanDefinition beanDefinition = new BeanDefinition();
            beanDefinition.setBeanName(beanName);
            beanDefinition.setBeanClassName(clazz.getName());
            beanDefinitions.add(beanDefinition);
        }
    }

    // 递归找出所有的class文件
    private void recursionFile(File classPath, String basePackage) {
        for (File file : classPath.listFiles()) {
            if (file.isDirectory()) {
                // 如果是文件夹，就需要继续递归
                recursionFile(file, basePackage + "." + file.getName());
            } else {
                if (!file.getName().endsWith(".class")) {
                    continue;
                }
                // 也就是找到了class文件   UserController.class
                // 拼接出class文件的全路径    com.djl.domain.controller.UserController   [.class]
                // Class.forName()
                String className = basePackage + "." + file.getName().replace(".class", "");
                classNames.add(className);
            }
        }
    }
}
